package agentspeakeditor.editors.common.parser;

import java.util.ArrayList;

import org.eclipse.jface.text.TextAttribute;
import org.eclipse.swt.graphics.Color;

import agentspeakeditor.editors.ColorManager;
import agentspeakeditor.editors.IASLColorConstants;
import agentspeakeditor.editors.common.AST.Program;
import agentspeakeditor.editors.common.scanner.Scanner;
import agentspeakeditor.editors.common.scanner.Token;
import agentspeakeditor.editors.common.scanner.TokenType;

public class Parser {

	private Token currentToken;
	private ColorManager manager;
	private Scanner scanner;
	private boolean hasErrors;
	private ArrayList<Token> tokenList;
	
	public Parser(Scanner scanner){
		this.scanner = scanner;
		manager = scanner.getManager();
		hasErrors = false;
	}
	
	private void accept(TokenType kind, Color color, int negro) {
		// If the current token kind is equal to the expected one
		// Gets next token
		if(this.currentToken.getKind() == kind) {
			currentToken.setData(new TextAttribute(color, null, negro));
		// If not
		// Raises an exception
		}else {
			currentToken.setData(manager.getColor(IASLColorConstants.DEFAULT));
		}
		tokenList.add(currentToken);
		this.currentToken = (Token) this.scanner.getNextToken();
	}
	
	private void acceptIt(Color color, int negro) {
		currentToken.setData(new TextAttribute(color, null, negro));
		tokenList.add(currentToken);
		currentToken = (Token) this.scanner.getNextToken();
	}
	
	public ArrayList<Token> parse(){
		tokenList = new ArrayList<>();	
		currentToken = (Token) this.scanner.getNextToken();
		
		parseLine();
		while(currentToken.getKind() != TokenType.EOT) {
			acceptIt(manager.getColor(IASLColorConstants.DEFAULT), 0);
		}
		accept(TokenType.EOT, null, 0);
		return tokenList;
	}
	
	private void parseLine(){
		Color color = null;
		
		if (currentToken.getKind() == TokenType.EXC) {
			acceptIt(manager.getColor(IASLColorConstants.ASL_DESIRE), 0);
			accept(TokenType.ID, manager.getColor(IASLColorConstants.ASL_DESIRE), 0);
			accept(TokenType.PON, manager.getColor(IASLColorConstants.ASL_DESIRE), 0);
		}
		else if (currentToken.getKind() == TokenType.ID) {
			acceptIt(manager.getColor(IASLColorConstants.BELIEF), 0);
			accept(TokenType.PARE, null, 0);
			accept(TokenType.NUM, manager.getColor(IASLColorConstants.NUMBER), 0);
			
			accept(TokenType.PARD, null, 0);
			accept(TokenType.PON, manager.getColor(IASLColorConstants.BLUEMOON), 0);
		}
		else{
			if(currentToken.getKind() == TokenType.MAIS || currentToken.getKind() == TokenType.MENOS){
				color = manager.getColor(IASLColorConstants.TRIGGER_EVENT2);
				acceptIt(color, 0);				
			} else if(currentToken.getKind() == TokenType.MAIS_EXC || currentToken.getKind() == TokenType.MENOS_EXC || 
					currentToken.getKind() == TokenType.MAIS_INT || currentToken.getKind() == TokenType.MENOS_INT) {
				color = manager.getColor(IASLColorConstants.TRIGGER_EVENT1);
				acceptIt(color, 0);
			}
			accept(TokenType.ID, color, 0);
			parseContext();
			parseBody();
			accept(TokenType.PON, manager.getColor(IASLColorConstants.BLUEMOON), 0);
			accept(TokenType.CR, manager.getColor(IASLColorConstants.DEFAULT), 0);
			accept(TokenType.EOL, manager.getColor(IASLColorConstants.DEFAULT), 0);
		}
	}
	
	private void parseContext() {
		Color color = manager.getColor(IASLColorConstants.BLUEMOON);
		if(currentToken.getKind() == TokenType.DPON) {
			acceptIt(color, 0);
			if(currentToken.getKind() == TokenType.TRUE || currentToken.getKind() == TokenType.FALSE) {
				acceptIt(manager.getColor(IASLColorConstants.RESERVED_WORD), 1);
			} else
				parseExpr();			
		}
	}
	
	private void parseBody(){	
		if(currentToken.getKind() == TokenType.SET){
			acceptIt(manager.getColor(IASLColorConstants.BLUEMOON), 0);
			parseCommand();
			while(currentToken.getKind() == TokenType.PVIR) {
				acceptIt(manager.getColor(IASLColorConstants.DEFAULT), 0);
				parseCommand();
			}
		}
	}
	
	private void parseExpr() {
		parseLogicExprBase();
		while (currentToken.getKind() == TokenType.E || currentToken.getKind() == TokenType.OU) {
			acceptIt(manager.getColor(IASLColorConstants.DEFAULT), 1);
			parseLogicExprBase();
		}
	}
	
	private void parseLogicExprBase() {
		Color color = null;
		if (currentToken.getKind() == TokenType.ID) {
			color = manager.getColor(IASLColorConstants.RESERVED_WORD);
			acceptIt(color, 0);
			if (currentToken.getKind() == TokenType.MAIOR || currentToken.getKind() == TokenType.MAIG ||
					currentToken.getKind() == TokenType.MENOR || currentToken.getKind() == TokenType.MEIG ||
					currentToken.getKind() == TokenType.IG || currentToken.getKind() == TokenType.DIF) {
				acceptIt(manager.getColor(IASLColorConstants.DEFAULT), 0);
				accept(TokenType.ID, color, 0);
			}
		} else if (currentToken.getKind() == TokenType.NOT) {
			acceptIt(manager.getColor(IASLColorConstants.LOGIC_OPERATOR), 1);
			parseExpr();
		} else if (currentToken.getKind() == TokenType.PARE) {
			acceptIt(manager.getColor(IASLColorConstants.DEFAULT), 0);
			parseExpr();
			accept(TokenType.PARD, manager.getColor(IASLColorConstants.DEFAULT), 0);
		}
		return;
	}
	
	private void parseCommand() {				
		if(currentToken.getKind() == TokenType.PON){
			acceptIt(manager.getColor(IASLColorConstants.COMMAND),0);
		}					
		accept(TokenType.ID, manager.getColor(IASLColorConstants.COMMAND),0);
		accept(TokenType.PARE, manager.getColor(IASLColorConstants.DEFAULT),0);
		accept(TokenType.ID, manager.getColor(IASLColorConstants.IDLIST), 0);
		
		while(currentToken.getKind() == TokenType.VIR){
			acceptIt(manager.getColor(IASLColorConstants.DEFAULT), 0);
			accept(TokenType.ID, manager.getColor(IASLColorConstants.IDLIST), 0);
		}
		accept(TokenType.PARD, manager.getColor(IASLColorConstants.DEFAULT),0);
	}
	
}
